home *** CD-ROM | disk | FTP | other *** search
/ Sun Solutions 1997 April to September / Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso / products / Hyperion / src / plat_osf1.c < prev    next >
C/C++ Source or Header  |  1997-02-26  |  13KB  |  593 lines

  1. /*
  2.  * @(#)plat_osf1.c    1.2    4/8/94
  3.  *
  4.  * OSF  drive control routines.
  5.  */
  6. static char *ident = "@(#)plat_osf1.c    1.2 4/8/94";
  7.  
  8. #ifdef OSF
  9.  
  10. #include <errno.h>
  11. #include <stdio.h>
  12. #include <sys/types.h>
  13. #include <fcntl.h>
  14. #include <sys/param.h>
  15. #include <sys/stat.h>
  16. #include <sys/time.h>
  17. #include <ustat.h>
  18. #include <string.h>
  19. /* #include <sys/rzdisk.h>
  20. #include <sys/cdrom.h>  */
  21. #include <io/cam/rzdisk.h>
  22. #include <io/cam/cdrom.h>
  23.  
  24. #include "struct.h"
  25.  
  26. /*
  27.  *   This structure will be filled with the TOC header and all entries.
  28.  * Ultrix doesn't seem to allow getting single TOC entries.
  29.  *                              - Chris Ross (cross@eng.umd.edu)
  30.  */
  31. struct cd_toc_header_and_entries {
  32.     struct cd_toc_header    cdth;
  33.     struct cd_toc_entry        cdte[CDROM_MAX_TRACK+1];
  34. };
  35.  
  36. void *malloc();
  37. char *strchr();
  38.  
  39. int    min_volume = 128;
  40. int    max_volume = 255;
  41.  
  42. extern char    *cd_device;
  43.  
  44. /*
  45.  * find_cdrom
  46.  *
  47.  * Determine the name of the CD-ROM device.
  48.  *
  49.  * Read through the boot records (via a call to uerf) and find the SCSI
  50.  * address of the CD-ROM.
  51.  */
  52. void
  53. find_cdrom()
  54. {
  55.     char    *data, *fgetline();
  56.     FILE    *uerf;
  57.     int    fds[2];
  58.     int    pid;
  59.  
  60.     pipe(fds);
  61.  
  62.     if ((pid = fork()) == 0) {
  63.         close(fds[0]);
  64.         dup2(fds[1], 1);
  65.         execl("/etc/uerf", "uerf", "-R", "-r", "300", NULL);
  66.         execl("/usr/sbin/uerf", "uerf", "-R", "-r", "300", NULL);
  67.         _exit(1);
  68.     } else if (pid < 0) {
  69.         perror("fork");
  70.         exit(1);
  71.     }
  72.  
  73.     close(fds[1]);
  74.     uerf = fdopen(fds[0], "r");
  75.  
  76.     while (data = fgetline(uerf))
  77.         if (strstr(data, "RRD42")) {
  78.             char    *device;
  79.  
  80.             cd_device = (char *)malloc(sizeof("/dev/rrz##c"));
  81.             strcpy(cd_device, "/dev/r");
  82.             device = strstr(data, "rz");
  83.             device[(int)(strchr(device, ' ') - device)] = '\0';
  84.             strcat(cd_device, device);
  85.             strcat(cd_device, "c");
  86.             break;
  87.         }
  88.  
  89.     fclose(uerf);
  90.  
  91.     if (cd_device == NULL) {
  92.         fprintf(stderr,
  93.             "No cdrom (RRD42) is installed on this system\n");
  94.         exit(1);
  95.     }
  96.  
  97.     kill(pid, 15);
  98.     (void)wait((int *)NULL);
  99. }
  100.  
  101. /*
  102.  * Initialize the drive.  A no-op for the generic driver.
  103.  */
  104. int
  105. gen_init(d)
  106.     struct wm_drive    *d;
  107. {
  108.     return (0);
  109. }
  110.  
  111. /*
  112.  * Get the number of tracks on the CD.
  113.  */
  114. int
  115. gen_get_trackcount(d, tracks)
  116.     struct wm_drive    *d;
  117.     int        *tracks;
  118. {
  119.     struct cd_toc_header    hdr;
  120.  
  121.     if (ioctl(d->fd, CDROM_TOC_HEADER, &hdr))
  122.         return (-1);
  123.  
  124.     *tracks = hdr.th_ending_track;
  125.  
  126.     return (0);
  127. }
  128.  
  129. /*
  130.  * Get the start time and mode (data or audio) of a track.
  131.  *
  132.  * XXX - this should get cached, but that means keeping track of ejects.
  133.  */
  134. int
  135. gen_get_trackinfo(d, track, data, startframe)
  136.     struct wm_drive    *d;
  137.     int        track, *data, *startframe;
  138. {
  139.     struct cd_toc                toc;
  140.     struct cd_toc_header            hdr;
  141.     struct cd_toc_header_and_entries    toc_buffer;
  142.  
  143.     if (ioctl(d->fd, CDROM_TOC_HEADER, &hdr))
  144.         return (-1);
  145.  
  146.     bzero((char *)&toc_buffer, sizeof(toc_buffer));
  147.     toc.toc_address_format = CDROM_MSF_FORMAT;
  148.     toc.toc_starting_track = 0;
  149.     toc.toc_alloc_length = (u_short)(((hdr.th_data_len1 << 8) +
  150.                     hdr.th_data_len0) & 0xfff) + 2;
  151.     toc.toc_buffer = (caddr_t)&toc_buffer;
  152.  
  153.     if (ioctl(d->fd, CDROM_TOC_ENTRYS, &toc))
  154.         return (-1);
  155.  
  156.     if (track == 0)
  157.         track = hdr.th_ending_track + 1;
  158.  
  159.     *data = (toc_buffer.cdte[track-1].te_control & CDROM_DATA_TRACK) ? 1:0;
  160.     *startframe = toc_buffer.cdte[track - 1].te_absaddr.msf.m_units*60*75 +
  161.         toc_buffer.cdte[track - 1].te_absaddr.msf.s_units * 75 +
  162.         toc_buffer.cdte[track - 1].te_absaddr.msf.f_units;
  163.  
  164.     return (0);
  165. }
  166.  
  167. /*
  168.  * Get the number of frames on the CD.
  169.  */
  170. int
  171. gen_get_cdlen(d, frames)
  172.     struct wm_drive    *d;
  173.     int        *frames;
  174. {
  175.     int        tmp;
  176.  
  177.     return (gen_get_trackinfo(d, 0, &tmp, frames));
  178. }
  179.  
  180. /*
  181.  * Get the current status of the drive: the current play mode, the absolute
  182.  * position from start of disc (in frames), and the current track and index
  183.  * numbers if the CD is playing or paused.
  184.  */
  185. int
  186. gen_get_drive_status(d, oldmode, mode, pos, track, index)
  187.     struct wm_drive    *d;
  188.     enum cd_modes    oldmode, *mode;
  189.     int        *pos, *track, *index;
  190. {
  191.     struct cd_sub_channel        sc;
  192.     struct cd_subc_channel_data    scd;
  193.  
  194.     /* If we can't get status, the CD is ejected, so default to that. */
  195.     *mode = EJECTED;
  196.  
  197.     sc.sch_address_format    = CDROM_MSF_FORMAT;
  198.     sc.sch_data_format    = CDROM_CURRENT_POSITION;
  199.     sc.sch_track_number    = 0;
  200.     sc.sch_alloc_length    = sizeof(scd);
  201.     sc.sch_buffer        = (caddr_t)&scd;
  202.  
  203.     /* Is the device open? */
  204.     if (d->fd < 0)
  205.     {
  206.         switch (wmcd_open(d)) {
  207.         case -1:    /* error */
  208.             return (-1);
  209.  
  210.         case 1:        /* retry */
  211.             return (0);
  212.         }
  213.     }
  214.  
  215.     if (ioctl(d->fd, CDROM_READ_SUBCHANNEL, &sc))
  216.         return (0);    /* ejected */
  217.  
  218.     switch (scd.scd_header.sh_audio_status) {
  219.     case AS_PLAY_IN_PROGRESS:
  220.         *mode = PLAYING;
  221. dopos:
  222.         *pos = scd.scd_position_data.scp_absaddr.msf.m_units * 60 * 75 +
  223.             scd.scd_position_data.scp_absaddr.msf.s_units * 75 +
  224.             scd.scd_position_data.scp_absaddr.msf.f_units;
  225.         *track = scd.scd_position_data.scp_track_number;
  226.         *index = scd.scd_position_data.scp_index_number;
  227.         break;
  228.  
  229.     case AS_PLAY_PAUSED:
  230.         if (oldmode == PLAYING || oldmode == PAUSED)
  231.         {
  232.             *mode = PAUSED;
  233.             goto dopos;
  234.         }
  235.         else
  236.             *mode = STOPPED;
  237.         break;
  238.  
  239.     case AS_PLAY_COMPLETED:
  240.         *mode = TRACK_DONE; /* waiting for next track. */
  241.         break;
  242.  
  243.     case AS_NO_STATUS:
  244.         *mode = STOPPED;
  245.         break;
  246.     }
  247.  
  248.     return (0);
  249. }
  250.  
  251. /*
  252.  * scale_volume(vol, max)
  253.  *
  254.  * Return a volume value suitable for passing to the CD-ROM drive.  "vol"
  255.  * is a volume slider setting; "max" is the slider's maximum value.
  256.  *
  257.  * On Sun and DEC CD-ROM drives, the amount of sound coming out the jack
  258.  * increases much faster toward the top end of the volume scale than it
  259.  * does at the bottom.  To make up for this, we make the volume scale look
  260.  * sort of logarithmic (actually an upside-down inverse square curve) so
  261.  * that the volume value passed to the drive changes less and less as you
  262.  * approach the maximum slider setting.  The actual formula looks like
  263.  *
  264.  *     (max^2 - (max - vol)^2) * (max_volume - min_volume)
  265.  * v = --------------------------------------------------- + min_volume
  266.  *                           max^2
  267.  *
  268.  * If your system's volume settings aren't broken in this way, something
  269.  * like the following should work:
  270.  *
  271.  *    return ((vol * (max_volume - min_volume)) / max + min_volume);
  272.  */
  273. scale_volume(vol, max)
  274.     int    vol, max;
  275. {
  276.     return ((max * max - (max - vol) * (max - vol)) *
  277.         (max_volume - min_volume) / (max * max) + min_volume);
  278. }
  279.  
  280. /*
  281.  * Set the volume level for the left and right channels.  Their values
  282.  * range from 0 to 100.
  283.  */
  284. int
  285. gen_set_volume(d, left, right)
  286.     struct wm_drive    *d;
  287.     int        left, right;
  288. {
  289.     struct cd_playback        pb;
  290.     struct cd_playback_status    ps;
  291.     struct cd_playback_control    pc;
  292.  
  293.     left = scale_volume(left, 100);
  294.     right = scale_volume(right, 100);
  295.  
  296.     bzero((char *)&pb, sizeof(pb));
  297.     bzero((char *)&ps, sizeof(ps));
  298.     bzero((char *)&pc, sizeof(pc));
  299.  
  300.     pb.pb_alloc_length = sizeof(ps);
  301.     pb.pb_buffer = (caddr_t)&ps;
  302.  
  303.     if (ioctl(d->fd, CDROM_PLAYBACK_STATUS, &pb))
  304.         return (-1);
  305.  
  306.     pc.pc_chan0_select = ps.ps_chan0_select;
  307.     pc.pc_chan0_volume = (left < CDROM_MIN_VOLUME) ?
  308.         CDROM_MIN_VOLUME : (left > CDROM_MAX_VOLUME) ?
  309.         CDROM_MAX_VOLUME : left;
  310.     pc.pc_chan1_select = ps.ps_chan1_select;
  311.     pc.pc_chan1_volume = (right < CDROM_MIN_VOLUME) ?
  312.         CDROM_MIN_VOLUME : (right > CDROM_MAX_VOLUME) ?
  313.         CDROM_MAX_VOLUME : right;
  314.  
  315.     pb.pb_alloc_length = sizeof(pc);
  316.     pb.pb_buffer = (caddr_t)&pc;
  317.  
  318.     if (ioctl(d->fd, CDROM_PLAYBACK_CONTROL, &pb))
  319.         return (-1);
  320.  
  321.     return (0);
  322. }
  323.  
  324. /*
  325.  * Pause the CD.
  326.  */
  327. int
  328. gen_pause(d)
  329.     struct wm_drive    *d;
  330. {
  331.     return (ioctl(d->fd, CDROM_PAUSE_PLAY));
  332. }
  333.  
  334. /*
  335.  * Resume playing the CD (assuming it was paused.)
  336.  */
  337. int
  338. gen_resume(d)
  339.     struct wm_drive    *d;
  340. {
  341.     return (ioctl(d->fd, CDROM_RESUME_PLAY));
  342. }
  343.  
  344. /*
  345.  * Stop the CD.
  346.  */
  347. int
  348. gen_stop(d)
  349.     struct wm_drive *d;
  350. {
  351.     return (ioctl(d->fd, SCSI_STOP_UNIT));
  352. }
  353.  
  354. /*
  355.  * Play the CD from one position to another (both in frames.)
  356.  */
  357. int
  358. gen_play(d, start, end)
  359.     struct wm_drive    *d;
  360.     int        start, end;
  361. {
  362.     struct cd_play_audio_msf    msf;
  363.  
  364.     msf.msf_starting_M_unit    = start / (60*75);
  365.     msf.msf_starting_S_unit    = (start % (60*75)) / 75;
  366.     msf.msf_starting_F_unit    = start % 75;
  367.     msf.msf_ending_M_unit    = end / (60*75);
  368.     msf.msf_ending_S_unit    = (end % (60*75)) / 75;
  369.     msf.msf_ending_F_unit    = end % 75;
  370.  
  371.     if (ioctl(d->fd, SCSI_START_UNIT))
  372.         return (-1);
  373.     if (ioctl(d->fd, CDROM_PLAY_MSF, &msf))
  374.         return (-2);
  375.  
  376.     return (0);
  377. }
  378.  
  379. /*
  380.  * Eject the current CD, if there is one.
  381.  */
  382. int
  383. gen_eject(d)
  384.     struct wm_drive    *d;
  385. {
  386.     /* On some systems, we can check to see if the CD is mounted. */
  387.     struct stat    stbuf;
  388.     struct ustat    ust;
  389.  
  390.     if (fstat(d->fd, &stbuf) != 0)
  391.         return (-2);
  392.  
  393.     /* Is this a mounted filesystem? */
  394.     if (ustat(stbuf.st_rdev, &ust) == 0)
  395.         return (-3);
  396.  
  397.     return (ioctl(d->fd, CDROM_EJECT_CADDY));
  398. }
  399.  
  400. /*
  401.  * unscale_volume(cd_vol, max)
  402.  *
  403.  * Given a value between min_volume and max_volume, return the volume slider
  404.  * value needed to achieve that value.
  405.  *
  406.  * Rather than perform floating-point calculations to reverse the above
  407.  * formula, we simply do a binary search of scale_volume()'s return values.
  408.  */
  409. static int
  410. unscale_volume(cd_vol, max)
  411.     int    cd_vol, max;
  412. {
  413.     int    vol = 0, top = max, bot = 0, scaled;
  414.  
  415.     while (bot <= top)
  416.     {
  417.         vol = (top + bot) / 2;
  418.         scaled = scale_volume(vol, max);
  419.         if (cd_vol == scaled)
  420.             break;
  421.         if (cd_vol < scaled)
  422.             top = vol - 1;
  423.         else
  424.             bot = vol + 1;
  425.     }
  426.     
  427.     if (vol < 0)
  428.         vol = 0;
  429.     else if (vol > max)
  430.         vol = max;
  431.  
  432.     return (vol);
  433. }
  434.  
  435. /*
  436.  * Read the initial volume from the drive, if available.  Each channel
  437.  * ranges from 0 to 100, with -1 indicating data not available.
  438.  */
  439. int
  440. gen_get_volume(d, left, right)
  441.     struct wm_drive    *d;
  442.     int        *left, *right;
  443. {
  444.     struct cd_playback        pb;
  445.     struct cd_playback_status    ps;
  446.  
  447.     bzero((char *)&pb, sizeof(pb));
  448.     bzero((char *)&ps, sizeof(ps));
  449.  
  450.     pb.pb_alloc_length = sizeof(ps);
  451.     pb.pb_buffer = (caddr_t)&ps;
  452.  
  453.     if (d->fd >= 0)
  454.     {
  455.         if (ioctl(d->fd, CDROM_PLAYBACK_STATUS, &pb))
  456.             *left = *right = -1;
  457.         else
  458.         {
  459.             *left = unscale_volume(ps.ps_chan0_volume, 100);
  460.             *right = unscale_volume(ps.ps_chan1_volume, 100);
  461.         }
  462.     }
  463.     else
  464.         *left = *right = -1;
  465.  
  466.     return (0);
  467. }
  468.  
  469. /*
  470.  * Send an arbitrary SCSI command to a device.
  471.  */
  472. int
  473. wm_scsi(d, cdb, cdblen, retbuf, retbuflen, getreply)
  474.     struct wm_drive    *d;
  475.     unsigned char    *cdb;
  476.     int        cdblen;
  477.     void        *retbuf;
  478.     int        retbuflen;
  479.     int        getreply;
  480. {
  481.     /* ULTRIX doesn't have a SCSI passthrough interface, does it? */
  482.     return (-1);
  483. }
  484.  
  485. /*
  486.  * fgetline()
  487.  *
  488.  *   Simulate fgets, but joining continued lines in the output of uerf.
  489.  */
  490.  
  491. #define BUF_SIZE        85              /* Max length of a (real) line */
  492.  
  493. char *
  494. fgetline(fp)
  495. FILE    *fp;
  496. {
  497.         static char     *retval = NULL;
  498.         static char     holdbuf[BUF_SIZE + 1];
  499.         char            tmp[BUF_SIZE + 1];
  500.         char            *stmp;
  501.  
  502.         if (!retval) {
  503.                 retval = malloc(BUF_SIZE * 3);  /* 3 lines can be joined */
  504.                 if (!retval)
  505.                         return(NULL);
  506.                 else
  507.                         *retval = '\0';
  508.         }
  509.  
  510.         if (*holdbuf) {
  511.                 strcpy(retval, holdbuf);
  512.                 retval[strlen(retval)-1] = '\0';
  513.                 memset(holdbuf, 0, BUF_SIZE+1);
  514.         }
  515.         while (fgets(tmp, BUF_SIZE, fp)) {
  516.                 stmp = tmp + strspn(tmp, " \t");
  517.                 if (*stmp == '_') {                     /* Continuation line */
  518.             retval[strlen(retval)-1] = '\0';   /* Trim off C/R */
  519.                         strcat(retval, stmp+1);
  520.                 } else {
  521.                         if (*retval) {
  522.                                 strcpy(holdbuf, tmp);
  523.                                 holdbuf[strlen(holdbuf)-1] = -1;
  524.                                 return retval;
  525.                         } else {             /* First line read, keep reading */
  526.                                 strcat(retval, stmp);
  527.                                 retval[strlen(retval)-1] = '\0';
  528.                         }
  529.                 }
  530.         }
  531.         return NULL;
  532. }
  533.  
  534. /*
  535.  * Open the CD device and figure out what kind of drive is attached.
  536.  */
  537. int
  538. wmcd_open(d)
  539.     struct wm_drive    *d;
  540. {
  541.     int        fd;
  542.     static int    warned = 0;
  543.  
  544.     if (d->fd >= 0)        /* Device already open? */
  545.         return (0);
  546.  
  547.     if (cd_device == NULL)
  548.         find_cdrom();
  549.  
  550.     d->fd = open(cd_device, 0);
  551.     if (d->fd < 0)
  552.     {
  553.         if (errno == EACCES)
  554.         {
  555.             if (!warned)
  556.             {
  557.                 fprintf(stderr,
  558.         "As root, please run\n\nchmod 666 %s\n\n%s\n", cd_device,
  559.         "to give yourself permission to access the CD-ROM device.");
  560.                 warned++;
  561.             }
  562.         }
  563.         else if (errno != EINTR)
  564.         {
  565.             perror(cd_device);
  566.             exit(1);
  567.         }
  568.  
  569.         /* No CD in drive. */
  570.         return (1);
  571.     }
  572.  
  573.     if (warned)
  574.     {
  575.         warned = 0;
  576.         fprintf(stderr, "Thank you.\n");
  577.     }
  578.  
  579.     /* Now fill in the relevant parts of the wm_drive structure. */
  580.     fd = d->fd;
  581.     *d = *(find_drive_struct("", "", ""));
  582.     d->fd = fd;
  583.  
  584.     (d->init)(d);
  585.  
  586.     return (0);
  587. }
  588.  
  589. void
  590. keep_cd_open() { }
  591.  
  592. #endif
  593.